package com.yeyks.rocketmq.service.customer;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.aliyun.openservices.ons.api.Action;
import com.aliyun.openservices.ons.api.ConsumeContext;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.MessageListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.yeyks.common.constants.OrderHeadExtraInfoConstant;
import com.yeyks.common.constants.hotel.HotelSourceType;
import com.yeyks.common.dto.mq.GrabTheOrderSuccessMessage;
import com.yeyks.common.dto.mq.GrabTheOrderSuccessWebsocketMessage;
import com.yeyks.common.em.WebSocketTypeEnum;
import com.yeyks.common.utils.FormatUtils;
import com.yeyks.commonReference.append.rocketmq.pojo.RocketMQWebsocketBasePojo;
import com.yeyks.commonReference.append.rocketmq.service.producer.MQProducerService;
import com.yeyks.commonReference.append.sms.SmsService;
import com.yeyks.commonReference.service.account.AccountInfoService;
import com.yeyks.commonReference.service.config.ConfigService;
import com.yeyks.commonReference.service.order.OrderHeadService;
import com.yeyks.commonReference.service.order.OrderPickRecordService;
import com.yeyks.config.pojo.param.WebConfigurationSystemVersionParam;
import com.yeyks.config.service.WebConfigurationService;
import com.yeyks.order.dal.domain.OrderHead;
import com.yeyks.order.dal.domain.OrderPickRecord;
import com.yeyks.websocket.SendMessageBean;
import com.yeyks.websocket.WebSocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author fuchangshuai
 * @date 2019/08/09 16:06
 */
@Slf4j
@Component
public class CToWebOrderSuccessListener implements MessageListener {
    @Autowired
    private OrderHeadService orderHeadService;
    @Autowired
    private OrderPickRecordService orderPickRecordService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private MQProducerService mqProducerService;
    @Autowired
    private AccountInfoService accountInfoService;
    @Autowired
    private CommonSendService commonSendService;
    @Autowired
    private WebSocket webSocket;
    @Autowired
    private SmsService smsService;
    @Autowired
    private WebConfigurationService webConfigurationService;

    @Override
    public Action consume(Message message, ConsumeContext consumeContext) {
        try {
            Long startTime = System.currentTimeMillis();
            byte[] body = message.getBody();
            //获取到接收的消息，由于接收到的是byte数组，所以需要转换成字符串
            String msg = new String(body);
            GrabTheOrderSuccessMessage successMessage = JSONUtil.toBean(msg, GrabTheOrderSuccessMessage.class);
            if (2 == successMessage.getType()) {
                //发送消息到mq，b端web端统一监听b2c订单下单成功并处理逻辑
                sendB2cOrderSuccess(successMessage.getOrderNo());

            } else {
                //抢单处理业务逻辑(cn只有抢单的)
                disposeLogic(successMessage);
            }
            log.info("下单成功：监听到的消息：message = {}", msg);
            Long endTime = System.currentTimeMillis();
            log.info("下单成功：单次消费耗时：" + (endTime - startTime) / 1000);
        } catch (Exception e) {
            log.error("MessageListener.consume error:" + e.getMessage(), e);
        }
        log.info("MessageListener.Receive message");
        //如果想测试消息重投的功能,可以将Action.CommitMessage 替换成Action.ReconsumeLater
        return Action.CommitMessage;
    }

    /**
     * 处理监听逻辑
     *
     * @param successMessage
     */
    private void disposeLogic(GrabTheOrderSuccessMessage successMessage) {
        try {
            //通过订单号查询订单
            OrderHead orderHead = orderHeadService.getByOrderNo(successMessage.getOrderNo());
            if (null == orderHead) {
                log.info("抢单成功：通过订单号查询的订单为空orderNo = {}", successMessage.getOrderNo());
                return;
            }
            //获取用户发起抢单的时间戳
            Long stamp = getStamp(orderHead);
            //查询到下单用户对应的抢单记录(判断该下单的是手动的还是自动的)
            OrderPickRecord orderSuccessRecord = orderPickRecordService.getOne(new QueryWrapper<OrderPickRecord>()
                    .eq(OrderPickRecord.USER_ID, orderHead.getUserId())
                    .eq(OrderPickRecord.TIMESTAMP, stamp)
                    .eq(OrderPickRecord.HOTEL_ID, orderHead.getHotelId())
                    .eq(OrderPickRecord.ROOM_ID, orderHead.getRoomId()).last("limit 1"));
            if (null == orderSuccessRecord) {
                log.info("该订单不是自动抢单和手动抢单的订单orderNo = {}", orderHead.getOrderNo());
                return;
            }
            //通过时间戳和用户id查询所有的手动抢单的记录
            List<OrderPickRecord> manualOrderPickRecords = orderPickRecordService.list(new QueryWrapper<OrderPickRecord>()
                    .eq(OrderPickRecord.USER_ID, orderHead.getUserId())
                    .eq(OrderPickRecord.TIMESTAMP, stamp)
                    .eq(OrderPickRecord.MANUAL_PICK_ORDER, 1));
            //下单的是手动抢单的酒店
            if (1 == orderSuccessRecord.getManualPickOrder()) {
                if (null != manualOrderPickRecords && manualOrderPickRecords.size() > 0) {
                    //获取手动抢单中抢单失败的酒店
                    List<OrderPickRecord> failLists = manualOrderPickRecords.stream().filter(e -> !e.getHotelId().equals(orderSuccessRecord.getHotelId())).collect(Collectors.toList());
                    //手动抢单集合：给订单酒店推送抢单成功通知，给订单酒店的所有上级推送新订单通知，给非酒店订单推送抢单失败通知
                    webSocketSendMessage(failLists, orderSuccessRecord, orderHead.getOrderNo(), orderHead.getVipFlag());
                }
            }
            //下单的是自动抢单的酒店
            if (0 == orderSuccessRecord.getManualPickOrder()) {
                //给酒店的所有上级包括酒店推动新订单通知
                autoWebSocketSendMessage(orderHead, orderHead.getVipFlag());
                if (null != manualOrderPickRecords && manualOrderPickRecords.size() > 0) {
                    //给所有手动抢单的酒店推送抢单失败消息
                    commonSendService.sendFailMessage(manualOrderPickRecords, null);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("抢单成功：处理监听消息异常：msg = {}", successMessage);
        }
    }

    /**
     * 给自动抢单成功的酒店发送webSocket消息
     */
    private void autoWebSocketSendMessage(OrderHead orderHead, Integer vipFlag) {
        try {
            //通过酒店id获取酒店上级用户名
            List<Integer> userIds = null;
            if (HotelSourceType.YYKS.equals(orderHead.getSourceType())) {
                userIds = accountInfoService.selectParentIdByHotelId(orderHead.getHotelId());
            } else {
                userIds = Lists.newArrayList(1403);
            }
            //web端消息发送
            sendMqToUser(userIds, orderHead.getOrderNo(), vipFlag);
            //发送mq让B端监听
            String orderMsg = SendMessageBean.getOrderMsg(orderHead.getOrderNo(), vipFlag);
            RocketMQWebsocketBasePojo pojo = new RocketMQWebsocketBasePojo();
            pojo.setType(WebSocketTypeEnum.ORDER.value());
            pojo.setUserId(orderHead.getHotelId());
            pojo.setBody(orderMsg);
            mqProducerService.sendRobResultMsg(pojo);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("给自动抢单成功的酒店发送webSocket消息异常：hotelId = {}", orderHead.getHotelId());
        }
    }

    private void sendMqToUser(List<Integer> userIds, String orderNo, Integer vipFlag) {
        String orderMsg = SendMessageBean.getOrderMsg(orderNo, vipFlag);
        for (Integer userId : userIds) {
            //新订单消息对象
            RocketMQWebsocketBasePojo pojo = new RocketMQWebsocketBasePojo();
            pojo.setType(WebSocketTypeEnum.ORDER.value());
            pojo.setUserId(userId);
            pojo.setBody(orderMsg);
            //给该账户id推送新订单通知
            mqProducerService.sendWebsocketMsg(pojo);
            //通过账户id查询出来manageId为该账户id的账户
            List<Integer> childIds = accountInfoService.selectChildByManageId(userId);
            if (null != childIds) {
                for (Integer childId : childIds) {
                    pojo.setUserId(childId);
                    //给该账户对应的子账户推送新订单通知
//                    mqProducerService.sendWebsocketMsg(pojo);
                    webSocket.sendMessageToUser(childId, SendMessageBean.getOrderMsg(orderNo, vipFlag));
                }
            }

        }
        //todo JIP订单给客服发送短信
        if(vipFlag == 3){
            WebConfigurationSystemVersionParam param = new WebConfigurationSystemVersionParam();
            param.setKey("jip.order.customer.phone");
            param.setVersion(1);
            String phones = webConfigurationService.getValue(param);
            if(!StringUtils.isEmpty(phones)){
                String[] phoneList = phones.split(",");
                for(String phone : phoneList){
                    smsService.sendSmsToSysCustomer(phone);
                }
            }
        }
    }

    /**
     * 手动抢单集合：发送webSocket消息
     *
     * @param failLists          未抢单成功的酒店记录集合
     * @param orderSuccessRecord 抢单成功的酒店记录
     * @param orderNo            订单号
     */
    private void webSocketSendMessage(List<OrderPickRecord> failLists, OrderPickRecord orderSuccessRecord, String orderNo, Integer vipFlag) {
        try {
            //获取抢单成功抢单失败文案
            GrabTheOrderSuccessWebsocketMessage robOrderMsg = configService.getHotelRobOrderMsg();
            String phone = orderSuccessRecord.getPhone();
            if (null != phone) {
                phone = FormatUtils.phoneHide(phone);
            }
            String price = FormatUtils.fenToYuan(orderSuccessRecord.getUserShowPrice());
            String successMsg = FormatUtils.formatTemplate(robOrderMsg.getSuccessMsg(), ImmutableMap.of("phone", phone, "price", price));
            String failMsg = FormatUtils.formatTemplate(robOrderMsg.getFailMsg(), ImmutableMap.of("phone", phone, "price", price));
            Map<String, String> successMap = ImmutableMap.of("successMsg", successMsg, "orderNo", orderNo);
            Map<String, String> failMap = ImmutableMap.of("failMsg", failMsg);
            //抢单成功的酒店
            RocketMQWebsocketBasePojo pojo = new RocketMQWebsocketBasePojo();
            pojo.setType(WebSocketTypeEnum.ROB_ORDER_RESULT.value());
            pojo.setUserId(orderSuccessRecord.getOperatorId());
            pojo.setBody(JSONUtil.toJsonStr(successMap));
            //给酒店发送抢单成功通知
            mqProducerService.sendWebsocketMsg(pojo);
            //给酒店的所有上级发送抢单通知
            sendToHotelParentMsg(orderSuccessRecord.getHotelId(), orderNo, vipFlag);
            //发送mq让B端监听
            mqProducerService.sendRobResultMsg(pojo);
            //未抢单成功的酒店
            Set<OrderPickRecord> set = new TreeSet<>(Comparator.comparing(OrderPickRecord::getOperatorId));
            set.addAll(failLists);
            List<OrderPickRecord> collect = Lists.newArrayList(set);
            commonSendService.sendFailMessage(collect, failMap);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("给酒店发送抢单成功或者抢单失败异常：orderNo = {}", orderNo);
        }
    }

    /**
     * 给酒店的所有上级推送抢单成功通知
     *
     * @param hotelId
     * @param orderNo
     */
    private void sendToHotelParentMsg(Integer hotelId, String orderNo, Integer vipFlag) {
        try {
            //通过酒店id获取酒店上级用户名
            List<Integer> userIds = accountInfoService.selectExcludeParentIdByHotelId(hotelId);
            sendMqToUser(userIds, orderNo, vipFlag);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("给自动抢单成功的酒店发送webSocket消息异常：hotelId = {}", hotelId);
        }
    }

    /**
     * 通过订单获取用户下单时的时间戳
     *
     * @param orderHead
     * @return
     */
    private Long getStamp(OrderHead orderHead) {
        try {
            String extraInfo = orderHead.getExtraInfo();
            JSONObject jsonObject = JSONUtil.parseObj(extraInfo);
            return (Long) jsonObject.get(OrderHeadExtraInfoConstant.GRAB_THE_ORDER_TIMESTAMP);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 发送消息到mq，b端web端统一监听b2c订单下单成功并处理逻辑
     *
     * @param orderNo
     */
    private void sendB2cOrderSuccess(String orderNo) {
        //发送mq让B端监听
        String orderMsg = SendMessageBean.getB2cOrderSuccess(orderNo);
        RocketMQWebsocketBasePojo pojo = new RocketMQWebsocketBasePojo();
        pojo.setType(WebSocketTypeEnum.B2C_ORDER_SUCCESS.value());
        pojo.setBody(orderMsg);
        pojo.setOrderNo(orderNo);
        mqProducerService.sendWebsocketMsg(pojo);
        //发送mq让B端监听
        mqProducerService.sendRobResultMsg(pojo);

    }


}
